package org.geoscrape;

import static org.geoscrape.util.HtmlParser.getContent;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;

import org.geoscrape.util.HtmlParser;
import org.geoscrape.util.WebClient;

/**
 *
 */
public class Cacher implements Serializable
{
	private static final long serialVersionUID = -8770402232284898399L;
	private String profilePage;
	private String name;
	private Long id;
	private Long foundCaches;
	private Boolean premiumMember;

	public Cacher(String name, String url)
	{
		this.name = name;
		this.profilePage = url;
	}

	public Cacher(String name)
	{
		this.name = name;
	}

	public Cacher(Long id)
	{
		this.setId(id);
	}

	@Override
	public boolean equals(Object o)
	{
		if (o instanceof Cacher)
		{
			Cacher other = (Cacher) o;
			if (other.getId() != null && getId() != null)
			{
				return other.getId() == getId();
			}
			else if (other.getName() != null && getName() != null)
			{
				return other.getName().equals(getName());
			}

		}
		return false;
	}

	/**
	 * @return the profilePage
	 */
	public String getProfilePage()
	{
		return profilePage;
	}

	/**
	 * @param profilePage
	 *            the profilePage to set
	 */
	public void setProfilePage(String profilePage)
	{
		this.profilePage = profilePage;
	}

	/**
	 * @return the name
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name)
	{
		this.name = name;
	}

	/**
	 * @return the foundCaches
	 */
	public Long getFoundCaches()
	{
		return foundCaches;
	}

	/**
	 * @param foundCaches
	 *            the foundCaches to set
	 */
	public void setFoundCaches(Long foundCaches)
	{
		this.foundCaches = foundCaches;
	}

	/**
	 * @return the id
	 */
	public Long getId()
	{
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(Long id)
	{
		this.id = id;
	}

	/**
	 * @return the isPremiumMember
	 */
	public Boolean isPremiumMember()
	{
		return premiumMember;
	}

	/**
	 * @param isPremiumMember
	 *            the isPremiumMember to set
	 */
	public void setPremiumMember(Boolean isPremiumMember)
	{
		this.premiumMember = isPremiumMember;
	}

	private String retrieveProfilePage(Login login) throws IOException
	{
		String res = null;
		WebClient client = login.getClient();
		String formUrl = "http://www.geocaching.com/my/myfriends.aspx";
		client.setRequestMethod("GET");
		client.goTo(formUrl);
		String contents = client.getContentsAsString();
		HashMap<String, String> values = HtmlParser.getViewState(contents);
		values.put("ctl00$ContentBody$FindUserPanel1$txtUsername", getName());
		values.put("ctl00$ContentBody$FindUserPanel1$GetUsers", "Go");
		values.put("__EVENTTARGET", "");
		values.put("__EVENTARGUMENT", "");
		client.setRequestMethod("POST");
		client.submitForm(formUrl, values);

		contents = client.getContentsAsString();

		if (contents != null)
		{
			String sendMessageString = getContent("<span id=\"ctl00_ContentBody_SendMessagePanel1_lblEmailInfo\">",
					"</span>", contents);

			if (sendMessageString != null)
			{
				res = getContent("href=\"", "\">", sendMessageString);
			}
			else
			{
				// the 'send message' link was not found.
				// check if there are multiple matching users
				contents = getContent("ctl00$ContentBody$FindUserPanel1$ddListUsers", "</select>", contents);
				if (contents != null)
				{
					List<String> alternatives = HtmlParser.getAllInstances("<option value=\"", "</option>", contents);
					for (String alt : alternatives)
					{
						String[] split = alt.split("\">");
						if (split[1].equals(getName()))
						{
							res = "http://www.geocaching.com/profile/?guid=" + split[0];
							break;
						}
					}
				}
			}
		}

		return res;
	}

	private String retrieveByProfilePage(Login login) throws IOException
	{
		WebClient client = login.getClient();
		client.setRequestMethod("GET");
		client.goTo(getProfilePage());
		String content = client.getContentsAsString();
		return content;
	}

	private String retrieveById(Login login) throws IOException
	{
		String query = "http://www.geocaching.com/profile/?id=" + Long.toString(getId());
		WebClient client = login.getClient();
		client.setRequestMethod("GET");
		client.goTo(query);
		String content = client.getContentsAsString();
		return content;
	}

	private Long extractId(String content)
	{
		String idString = getContent("do=user_activity&amp;mid=", "\">", content);
		if (idString != null)
		{
			return Long.parseLong(idString);
		}
		return null;
	}

	private String extractName(String contents)
	{
		String name = getContent("ctl00_ContentBody_lblUserProfile", "span>", contents);
		if (name != null)
		{
			name = getContent(": ", "</", name);
			return name;
		}
		return null;
	}

	private String extractProfilePage(String contents)
	{
		String guid = getContent("ift/default.aspx?uguid=", "\">", contents);
		if (guid != null)
		{
			return "http://www.geocaching.com/profile/?guid=" + guid;
		}
		return null;
	}

	private Boolean extractPremiumMember(String contents)
	{
		String membership = getContent("ctl00_ContentBody_ProfilePanel1_lblStatusText", "</span>", contents);
		if (membership != null)
		{
			if (membership.contains("Premium"))
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		return null;
	}

	/**
	 * Populate the missing data in this object from the internet.
	 * 
	 * @param login
	 * @throws IOException
	 */
	public void populate(Login login) throws IOException
	{
		// don't populate if we don't have to
		if (getName() != null && getId() != null && isPremiumMember() != null && getProfilePage() != null)
		{
			return;
		}
		String profileContents = null;
		if (this.getProfilePage() != null)
		{
			// we have the guid, just grab the page
			profileContents = retrieveByProfilePage(login);
		}
		else if (this.getId() != null)
		{
			// no guid, but id number
			profileContents = retrieveById(login);
		}
		else if (this.getName() != null)
		{
			// neither guid nor id, so look up the name
			this.setProfilePage(retrieveProfilePage(login));
			profileContents = retrieveByProfilePage(login);
		}
		else
		{
			// not enough information to identify cacher.
			return;
		}

		if (getName() == null)
		{
			setName(extractName(profileContents));
		}
		if (getId() == null)
		{
			setId(extractId(profileContents));
		}
		if (getProfilePage() == null)
		{
			this.setProfilePage(extractProfilePage(profileContents));
		}
		if (isPremiumMember() == null)
		{
			setPremiumMember(extractPremiumMember(profileContents));
		}
	}

}
